Skip to content

lazy-auth-server: support mounting under a base path#683

Merged
ochafik merged 2 commits into
mainfrom
ochafik/lazy-auth-mount-aware
Jun 4, 2026
Merged

lazy-auth-server: support mounting under a base path#683
ochafik merged 2 commits into
mainfrom
ochafik/lazy-auth-mount-aware

Conversation

@ochafik
Copy link
Copy Markdown
Contributor

@ochafik ochafik commented Jun 2, 2026

What this does

Makes the lazy-auth example mountable inside another Express app (hostApp.use("/lazy-auth", createApp())), so an existing MCP server can host it at a sub-path of its own origin. Motivation: serving this example from example-remote-server alongside the other examples at /:slug/mcp, on its existing single-origin deployment (a follow-up PR there consumes this).

Why

createApp() built every advertised URL (AS metadata endpoints, PRM resource, WWW-Authenticate resource_metadata, consent approve link, elicitation callbacks) from the bare origin. Mounted under a sub-path, those URLs point at the host's root — colliding with the host's own OAuth endpoints. The observed failure is nasty: the 401 advertises https://host/auth/prm, which 404s, so SDK clients fall back to treating the host origin as the authorization server and users complete the wrong OAuth flow, ending in a 401 loop.

What changed

  • resolvePublicUrl() now appends Express's req.baseUrl (empty when standalone, so standalone behavior is unchanged). PUBLIC_URL, when set, must include the mount path.
  • New publicBaseHref() helper replaces all ${base.origin} joins.
  • DIST_DIR is now derived from import.meta.url instead of import.meta.filename/import.meta.dirname, which are undefined in some module-VM contexts (importing the package from jest threw at import time).
  • README documents the mounting pattern, including the root well-known rewrite hosts must add: RFC 8414/9728 path-insertion discovery URLs (/.well-known/oauth-authorization-server/lazy-auth) live at the origin root, outside the mount, and the TS SDK only tries that insertion form for oauth-authorization-server.

How it was verified

  • npm run --workspace examples/lazy-auth-server build (includes tsc --noEmit) and prettier pass.
  • Scripted end-to-end checks (23 assertions) across three configurations:
    • standalone at http://localhost:3097 — URLs identical to before (back-compat);
    • mounted at /lazy-auth inside a host app with colliding root /authorize + /.well-known/oauth-authorization-server routes — full 401 → PRM → AS discovery (insertion form) → PKCE → token → authed get_secret flow, TTL-scoped PRM, host routes untouched;
    • PUBLIC_URL=https://example.test/lazy-auth — advertised URLs use the configured base.
  • Also verified mounted inside an express@4 host (example-remote-server uses express@4; this package bundles express@5) — routing, req.baseUrl, and double body-parsing all behave.

After merge

Publish as 1.7.4 so example-remote-server can pick it up. Note: @modelcontextprotocol/server-transcript@1.7.3 appears to have been skipped by the 1.7.3 publish (npm has up to 1.7.2) — worth checking the publish workflow at the same time.

ochafik added 2 commits June 2, 2026 13:32
createApp() previously built every advertised URL (AS metadata
endpoints, PRM resource, WWW-Authenticate resource_metadata, consent
approve link, elicitation callbacks) from the bare origin, so mounting
the app inside another Express app — app.use("/lazy-auth",
createApp()) — advertised URLs that pointed at the host's root and
collided with the host's own OAuth endpoints.

Derive the public base URL from Express's req.baseUrl instead (empty
when standalone, so standalone behavior is unchanged), and treat
PUBLIC_URL as including any mount path. Document the mounting pattern,
including the root well-known rewrite hosts must add for RFC 8414/9728
path-insertion discovery.
import.meta.filename and import.meta.dirname are undefined in some
module-VM contexts (e.g. importing this package from jest), which made
createApp() throw at import time. import.meta.url is defined
everywhere; derive the dist directory from it instead.
@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented Jun 2, 2026

Open in StackBlitz

@modelcontextprotocol/ext-apps

npm i https://pkg.pr.new/@modelcontextprotocol/ext-apps@683

@modelcontextprotocol/server-basic-preact

npm i https://pkg.pr.new/@modelcontextprotocol/server-basic-preact@683

@modelcontextprotocol/server-basic-react

npm i https://pkg.pr.new/@modelcontextprotocol/server-basic-react@683

@modelcontextprotocol/server-basic-solid

npm i https://pkg.pr.new/@modelcontextprotocol/server-basic-solid@683

@modelcontextprotocol/server-basic-svelte

npm i https://pkg.pr.new/@modelcontextprotocol/server-basic-svelte@683

@modelcontextprotocol/server-basic-vanillajs

npm i https://pkg.pr.new/@modelcontextprotocol/server-basic-vanillajs@683

@modelcontextprotocol/server-basic-vue

npm i https://pkg.pr.new/@modelcontextprotocol/server-basic-vue@683

@modelcontextprotocol/server-budget-allocator

npm i https://pkg.pr.new/@modelcontextprotocol/server-budget-allocator@683

@modelcontextprotocol/server-cohort-heatmap

npm i https://pkg.pr.new/@modelcontextprotocol/server-cohort-heatmap@683

@modelcontextprotocol/server-customer-segmentation

npm i https://pkg.pr.new/@modelcontextprotocol/server-customer-segmentation@683

@modelcontextprotocol/server-debug

npm i https://pkg.pr.new/@modelcontextprotocol/server-debug@683

@modelcontextprotocol/server-lazy-auth

npm i https://pkg.pr.new/@modelcontextprotocol/server-lazy-auth@683

@modelcontextprotocol/server-map

npm i https://pkg.pr.new/@modelcontextprotocol/server-map@683

@modelcontextprotocol/server-pdf

npm i https://pkg.pr.new/@modelcontextprotocol/server-pdf@683

@modelcontextprotocol/server-scenario-modeler

npm i https://pkg.pr.new/@modelcontextprotocol/server-scenario-modeler@683

@modelcontextprotocol/server-shadertoy

npm i https://pkg.pr.new/@modelcontextprotocol/server-shadertoy@683

@modelcontextprotocol/server-sheet-music

npm i https://pkg.pr.new/@modelcontextprotocol/server-sheet-music@683

@modelcontextprotocol/server-system-monitor

npm i https://pkg.pr.new/@modelcontextprotocol/server-system-monitor@683

@modelcontextprotocol/server-threejs

npm i https://pkg.pr.new/@modelcontextprotocol/server-threejs@683

@modelcontextprotocol/server-transcript

npm i https://pkg.pr.new/@modelcontextprotocol/server-transcript@683

@modelcontextprotocol/server-video-resource

npm i https://pkg.pr.new/@modelcontextprotocol/server-video-resource@683

@modelcontextprotocol/server-wiki-explorer

npm i https://pkg.pr.new/@modelcontextprotocol/server-wiki-explorer@683

commit: 9110c2c

@ochafik ochafik force-pushed the ochafik/lazy-auth-mount-aware branch from 5ab6589 to 9110c2c Compare June 2, 2026 12:33
@ochafik
Copy link
Copy Markdown
Contributor Author

ochafik commented Jun 4, 2026

@ochafik ochafik merged commit 0ffe167 into main Jun 4, 2026
20 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant